package com.cblz.bd.server.core.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cblz.bd.common.core.constant.MinioUploadConstant;
import com.cblz.bd.common.core.entity.BaAdmin;
import com.cblz.bd.common.core.entity.BaAdminGroup;
import com.cblz.bd.common.core.entity.system.QueryRequest;
import com.cblz.bd.common.core.exception.BdAdminException;
import com.cblz.bd.common.core.exception.ValidateCodeException;
import com.cblz.bd.server.core.annotation.Log;
import com.cblz.bd.server.core.entity.LoginParams;
import com.cblz.bd.server.core.entity.dto.BaAdminDTO;
import com.cblz.bd.server.core.entity.vo.BaAdminManagerVO;
import com.cblz.bd.server.core.event.ClearCacheEventListen;
import com.cblz.bd.server.core.mapper.BaAdminMapper;
import com.cblz.bd.server.core.service.BaAdminGroupAccessService;
import com.cblz.bd.server.core.service.BaAdminGroupService;
import com.cblz.bd.server.core.service.BaAdminService;
import com.cblz.bd.server.utils.BcryptUtil;
import com.cblz.bd.server.utils.BdCaptchaUtil;
import com.cblz.bd.server.utils.CacheCleanUtil;
import com.cblz.bd.server.utils.MinioFilesUtil;
import io.vavr.control.Option;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;

/**
 * @author yanjieping
 * @description 针对表【ba_admin(管理员表)】的数据库操作Service实现
 * @createDate 2022-11-04 15:09:53
 */
@Slf4j
@Service("baAdminService")
@RequiredArgsConstructor
public class BaAdminServiceImpl extends ServiceImpl<BaAdminMapper, BaAdmin> implements BaAdminService {

    private final BdCaptchaUtil bdCaptchaUtil;
    private final CacheCleanUtil cacheCleanUtil;
    private final MinioFilesUtil minioFilesUtil;
    private final BaAdminGroupService baAdminGroupService;
    private final BaAdminGroupAccessService baAdminGroupAccessService;

    /**
     * 用户名密码校验
     *
     * @param loginParams
     * @return
     */
    @Override
    public SaTokenInfo usernamePasswordCheck(LoginParams loginParams) throws ValidateCodeException {
        // 校验验证码
        bdCaptchaUtil.check(loginParams.getKey(), loginParams.getCode());

        LambdaQueryWrapper<BaAdmin> lambdaQueryWrapper = new QueryWrapper<BaAdmin>().lambda();

        BaAdmin baAdmin = Option.of(this.getOne(lambdaQueryWrapper.eq(BaAdmin::getUsername, loginParams.getUsername()))).getOrElseThrow(() -> {
            bdCaptchaUtil.delCaptcha(loginParams.getKey());
            return new BdAdminException("未找到用户:" + loginParams.getUsername());
        });

        Option.of(baAdminGroupService.getBdAdminRulesByLoginId(baAdmin.getId())).getOrElse(() -> {
            log.warn("没有分配任何权限的用户：{} 进行登录操作。", baAdmin.getUsername());
            throw new BdAdminException("登录账户:「" + baAdmin.getUsername() + "」没有任何权限分配，请联系管理员");
        });

        if (BcryptUtil.decrypt(loginParams.getPassword(), baAdmin.getPassword())) {
            // 登录,是否为记住我模式
            StpUtil.login(baAdmin.getId(), loginParams.getKeep());
            // 获取token信息
            return StpUtil.getTokenInfo();
        }
        // 用户名密码不正确就删除验证码，让其失效
        bdCaptchaUtil.delCaptcha(loginParams.getKey());
        return null;
    }

    /**
     * 注销登录
     */
    @Override
    public void logout() {
        cacheCleanUtil.cleanCustomSession();
        StpUtil.logout();
    }

    /**
     * 清除缓存信息
     *
     * @return
     */
    @Override
    @Log(description = "清除缓存信息")
    @EventListener(classes = ClearCacheEventListen.class)
    public void clearCache() {
        cacheCleanUtil.cleanMenuCache(true, true, (String) null);
    }

    /**
     * 获取所有后台用户信息
     *
     * @return
     */
    @Override
    public Map<String, Object> getAllUserInfo(BaAdmin baAdminParam, QueryRequest queryRequest) {
        LambdaQueryWrapper<BaAdmin> queryWrapper = new LambdaQueryWrapper<>();
        //模糊查询id
        if (null != baAdminParam.getId()) {
            queryWrapper.like(BaAdmin::getId, baAdminParam.getId());
        }
        //模糊查询用户名
        if (StringUtils.isNotBlank(baAdminParam.getUsername())) {
            queryWrapper.like(BaAdmin::getUsername, baAdminParam.getUsername());
        }
        //模糊查询昵称
        if (StringUtils.isNotBlank(baAdminParam.getNickname())) {
            queryWrapper.like(BaAdmin::getNickname, baAdminParam.getNickname());
        }
        //模糊查询邮箱
        if (StringUtils.isNotBlank(baAdminParam.getEmail())) {
            queryWrapper.like(BaAdmin::getEmail, baAdminParam.getEmail());
        }
        //模糊查询手机号
        if (StringUtils.isNotBlank(baAdminParam.getMobile())) {
            queryWrapper.like(BaAdmin::getMobile, baAdminParam.getMobile());
        }
        //最后登录，时间选择器可单选
        if (null != baAdminParam.getLastlogintimeStartTime()) {
            queryWrapper.ge(BaAdmin::getLastlogintime, baAdminParam.getLastlogintimeStartTime());
        }
        if (null != baAdminParam.getLastlogintimeEndTime()) {
            queryWrapper.le(BaAdmin::getLastlogintime, baAdminParam.getLastlogintimeEndTime());
        }
        //创建时间，时间选择器可单选
        if (null != baAdminParam.getCreatetimeStartTime()) {
            queryWrapper.ge(BaAdmin::getCreatetime, baAdminParam.getCreatetimeStartTime());
        }
        if (null != baAdminParam.getCreatetimeEndTime()) {
            queryWrapper.le(BaAdmin::getCreatetime, baAdminParam.getCreatetimeEndTime());
        }
        //状态查询
        if (null != baAdminParam.getStatus()) {
            queryWrapper.eq(BaAdmin::getStatus, baAdminParam.getStatus());
        }

        Page<BaAdmin> page = new Page<>(queryRequest.getPageNum(), queryRequest.getPageSize());

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("total", baseMapper.selectPage(page, queryWrapper).getTotal());
        resultMap.put("allinfo", getUserGroupInfo(baseMapper.selectPage(page, queryWrapper).getRecords()));
        return resultMap;
    }

    /**
     * 上传管理员头像
     *
     * @param file 图片文件
     * @return
     */
    @Override
    @Log(description = "更新头像")
    public String uploadAdminAvatar(MultipartFile file) throws Exception {
        return Option.of(minioFilesUtil.uploadFile(file, MinioUploadConstant.ADMIN_FILES.getVal())).getOrElse(() -> {
            throw new BdAdminException("文件file不能为空");
        });

    }

    @Override
    public List<BaAdminManagerVO> getUserGroupInfo(List<BaAdmin> baAdmins) {
        return Option.of(baAdmins).getOrNull().stream().map(baAdmin -> {
            // 拿到用户对应的角色组
            List<BaAdminGroup> adminRulesByLoginId = baAdminGroupService.getBdAdminRulesByLoginId(baAdmin.getId());

            int[] groupIds = adminRulesByLoginId.stream().mapToInt(BaAdminGroup::getId).toArray();

            List<String> groupNames = new ArrayList<>(adminRulesByLoginId.stream().map(BaAdminGroup::getName).toList());

            return BeanUtil.copyProperties(baAdmin, BaAdminManagerVO.class).setGroup_arr(groupIds).setGroup_name_arr(groupNames);
        }).toList();
    }

    @Override
    public BaAdminManagerVO getById(Integer id) {
        BaAdmin baAdmin = Option.of(baseMapper.selectById(id)).getOrElseThrow(() -> new BdAdminException("找不到id:" + id + "的用户！"));
        baAdmin.setPassword(null);
        return getUserGroupInfo(List.of(baAdmin)).get(0);
    }

    @Override
    @Log(description = "新增管理员")
    @Transactional(rollbackFor = Exception.class)
    public void add(BaAdminDTO baAdmin) {
        baAdmin.setPassword(BcryptUtil.encrypt(baAdmin.getPassword()));
        baAdmin.setCreatetime(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
        save(baAdmin);
        //添加角色组信息
        baAdminGroupAccessService.add(baAdmin.getId(), baAdmin.getGroup_arr());
    }

    @Override
    @Log(description = "删除管理员")
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> ids) {
        ids.forEach(id -> {
            removeById(new LambdaQueryChainWrapper<>(baseMapper).eq(BaAdmin::getId, id).one());
        });
    }

    @Override
    @Log(description = "修改用户信息")
    @Transactional(rollbackFor = Exception.class)
    public void edit(BaAdminDTO baAdmin) {
        if (StringUtils.isNotBlank(baAdmin.getPassword())) {
            baAdmin.setPassword(BcryptUtil.encrypt(baAdmin.getPassword()));
        }
        baAdmin.setUpdatetime(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
        updateById(baAdmin);

        if (!Objects.isNull(baAdmin.getGroup_arr()) && baAdmin.getGroup_arr().isEmpty()) {
            //修改角色组信息
            //1.删除原角色组信息
            baAdminGroupAccessService.delete(baAdmin.getId());
            //2.新增现角色组信息
            baAdminGroupAccessService.add(baAdmin.getId(), baAdmin.getGroup_arr());
        }
    }

    
}




